//============================================================================
// Copyright (C) 2009-2013 Brett R. Jones
//
// Issued to public domain 2013
//
// brettjones1900@gmail.com
// http://www.p2panarchy.com
//============================================================================
#include <VxUtilLib/VxSktUtil.h>
#include <VxUtilLib/vx_debug.h>
#include <stdlib.h>

// list of ports register with icann etc
static U16 g_au16AllocatedPorts[] =
{
#include "VxAnyRandomPort.h"
};


//Check known registered ports
static BOOL IsPortRegistered( U16 u16Port )
{
	int iRangeCnt = sizeof( g_au16AllocatedPorts )/4;
	for( int i = 2; i < iRangeCnt; i+=2 )
	{
		if( (u16Port > g_au16AllocatedPorts[i]) &&
			(u16Port < g_au16AllocatedPorts[i]) )
		{
			// it is a port used by some application or agency
			return true;
		}
	}
	return false;
}

static bool VerifyPortList( void )
{
	if( sizeof( g_au16AllocatedPorts ) & 0x03 )
	{
		vx_assert( false );
	}
	U16 u16LastStartPort	= 0;
	U16 u16LastEndPort		= 0;
	BOOL bFirstRound = true;

	int iRangeCnt = sizeof( g_au16AllocatedPorts )/4;
	for( int i = 0; i < iRangeCnt; i+=2 )
	{
		if( g_au16AllocatedPorts[i] >  g_au16AllocatedPorts[i+1] )
		{
			return false;
		}
		if( bFirstRound )
		{
			u16LastStartPort = g_au16AllocatedPorts[i];
			u16LastEndPort = g_au16AllocatedPorts[i+1];
			bFirstRound = false;
		}
		else
		{
			if( (u16LastStartPort > g_au16AllocatedPorts[i]) ||
				(u16LastEndPort > g_au16AllocatedPorts[i]) )
			{
				return false;
			}
		}
	}
	return true;
}

//============================================================================
//! get a random tcp/ip port that is not in use
U16 VxGetRandomTcpPort( bool bAbove4000 )
{
	vx_assert( VerifyPortList() );
	// pick a random port
	U16 u16RandPort;

	for( int i = 0; i < 30000; i++ )
	{
		u16RandPort = (U16)rand();
		if( 0 == u16RandPort )
		{
			// zero not allowed
			continue;
		}
		if( bAbove4000 )
		{
			if( u16RandPort < 4000 )
			{
				continue;
			}
		}
		// now see if it has been registered 
		if( IsPortRegistered( u16RandPort ) )
		{
			// port was registered with ICAN as use by some app or something
			continue;
		}
		if( VxIsIpPortInUse( u16RandPort ))
		{
			continue;
		}
		// success
		return u16RandPort;

	}
	// if we got here we have tried 30000 times and failed.. give up
	log_msg( LOG_ERROR, "VxGetRandomTcpPort: could not find a port\n");
	return 0;
}
